/*
 * ID3v1 header parser
 * Copyright (c) 2003 Fabrice Bellard
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "id3v1.h"
#include "libavcodec/avcodec.h"
#include "libavutil/dict.h"

/* See Genre List at http://id3.org/id3v2.3.0 */
const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
      /*[0] =*/ "Blues",
      /*[1] =*/ "Classic Rock",
      /*[2] =*/ "Country",
      /*[3] =*/ "Dance",
      /*[4] =*/ "Disco",
      /*[5] =*/ "Funk",
      /*[6] =*/ "Grunge",
      /*[7] =*/ "Hip-Hop",
      /*[8] =*/ "Jazz",
      /*[9] =*/ "Metal",
     /*[10] =*/ "New Age",
     /*[11] =*/ "Oldies",
     /*[12] =*/ "Other",
     /*[13] =*/ "Pop",
     /*[14] =*/ "R&B",
     /*[15] =*/ "Rap",
     /*[16] =*/ "Reggae",
     /*[17] =*/ "Rock",
     /*[18] =*/ "Techno",
     /*[19] =*/ "Industrial",
     /*[20] =*/ "Alternative",
     /*[21] =*/ "Ska",
     /*[22] =*/ "Death Metal",
     /*[23] =*/ "Pranks",
     /*[24] =*/ "Soundtrack",
     /*[25] =*/ "Euro-Techno",
     /*[26] =*/ "Ambient",
     /*[27] =*/ "Trip-Hop",
     /*[28] =*/ "Vocal",
     /*[29] =*/ "Jazz+Funk",
     /*[30] =*/ "Fusion",
     /*[31] =*/ "Trance",
     /*[32] =*/ "Classical",
     /*[33] =*/ "Instrumental",
     /*[34] =*/ "Acid",
     /*[35] =*/ "House",
     /*[36] =*/ "Game",
     /*[37] =*/ "Sound Clip",
     /*[38] =*/ "Gospel",
     /*[39] =*/ "Noise",
     /*[40] =*/ "AlternRock",
     /*[41] =*/ "Bass",
     /*[42] =*/ "Soul",
     /*[43] =*/ "Punk",
     /*[44] =*/ "Space",
     /*[45] =*/ "Meditative",
     /*[46] =*/ "Instrumental Pop",
     /*[47] =*/ "Instrumental Rock",
     /*[48] =*/ "Ethnic",
     /*[49] =*/ "Gothic",
     /*[50] =*/ "Darkwave",
     /*[51] =*/ "Techno-Industrial",
     /*[52] =*/ "Electronic",
     /*[53] =*/ "Pop-Folk",
     /*[54] =*/ "Eurodance",
     /*[55] =*/ "Dream",
     /*[56] =*/ "Southern Rock",
     /*[57] =*/ "Comedy",
     /*[58] =*/ "Cult",
     /*[59] =*/ "Gangsta",
     /*[60] =*/ "Top 40",
     /*[61] =*/ "Christian Rap",
     /*[62] =*/ "Pop/Funk",
     /*[63] =*/ "Jungle",
     /*[64] =*/ "Native American",
     /*[65] =*/ "Cabaret",
     /*[66] =*/ "New Wave",
     /*[67] =*/ "Psychadelic", /* sic, the misspelling is used in the specification */
     /*[68] =*/ "Rave",
     /*[69] =*/ "Showtunes",
     /*[70] =*/ "Trailer",
     /*[71] =*/ "Lo-Fi",
     /*[72] =*/ "Tribal",
     /*[73] =*/ "Acid Punk",
     /*[74] =*/ "Acid Jazz",
     /*[75] =*/ "Polka",
     /*[76] =*/ "Retro",
     /*[77] =*/ "Musical",
     /*[78] =*/ "Rock & Roll",
     /*[79] =*/ "Hard Rock",
     /*[80] =*/ "Folk",
     /*[81] =*/ "Folk-Rock",
     /*[82] =*/ "National Folk",
     /*[83] =*/ "Swing",
     /*[84] =*/ "Fast Fusion",
     /*[85] =*/ "Bebob",
     /*[86] =*/ "Latin",
     /*[87] =*/ "Revival",
     /*[88] =*/ "Celtic",
     /*[89] =*/ "Bluegrass",
     /*[90] =*/ "Avantgarde",
     /*[91] =*/ "Gothic Rock",
     /*[92] =*/ "Progressive Rock",
     /*[93] =*/ "Psychedelic Rock",
     /*[94] =*/ "Symphonic Rock",
     /*[95] =*/ "Slow Rock",
     /*[96] =*/ "Big Band",
     /*[97] =*/ "Chorus",
     /*[98] =*/ "Easy Listening",
     /*[99] =*/ "Acoustic",
    /*[100] =*/ "Humour",
    /*[101] =*/ "Speech",
    /*[102] =*/ "Chanson",
    /*[103] =*/ "Opera",
    /*[104] =*/ "Chamber Music",
    /*[105] =*/ "Sonata",
    /*[106] =*/ "Symphony",
    /*[107] =*/ "Booty Bass",
    /*[108] =*/ "Primus",
    /*[109] =*/ "Porn Groove",
    /*[110] =*/ "Satire",
    /*[111] =*/ "Slow Jam",
    /*[112] =*/ "Club",
    /*[113] =*/ "Tango",
    /*[114] =*/ "Samba",
    /*[115] =*/ "Folklore",
    /*[116] =*/ "Ballad",
    /*[117] =*/ "Power Ballad",
    /*[118] =*/ "Rhythmic Soul",
    /*[119] =*/ "Freestyle",
    /*[120] =*/ "Duet",
    /*[121] =*/ "Punk Rock",
    /*[122] =*/ "Drum Solo",
    /*[123] =*/ "A capella",
    /*[124] =*/ "Euro-House",
    /*[125] =*/ "Dance Hall",
    /*[126] =*/ "Goa",
    /*[127] =*/ "Drum & Bass",
    /*[128] =*/ "Club-House",
    /*[129] =*/ "Hardcore",
    /*[130] =*/ "Terror",
    /*[131] =*/ "Indie",
    /*[132] =*/ "BritPop",
    /*[133] =*/ "Negerpunk",
    /*[134] =*/ "Polsk Punk",
    /*[135] =*/ "Beat",
    /*[136] =*/ "Christian Gangsta",
    /*[137] =*/ "Heavy Metal",
    /*[138] =*/ "Black Metal",
    /*[139] =*/ "Crossover",
    /*[140] =*/ "Contemporary Christian",
    /*[141] =*/ "Christian Rock",
    /*[142] =*/ "Merengue",
    /*[143] =*/ "Salsa",
    /*[144] =*/ "Thrash Metal",
    /*[145] =*/ "Anime",
    /*[146] =*/ "JPop",
    /*[147] =*/ "SynthPop",
};

static void get_string(AVFormatContext *s, const char *key,
                       const uint8_t *buf, int buf_size)
{
    int i, c;
    char *q, str[512];

    q = str;
    for(i = 0; i < buf_size; i++) {
        c = buf[i];
        if (c == '\0')
            break;
        if ((q - str) >= sizeof(str) - 1)
            break;
        *q++ = c;
    }
    *q = '\0';

    if (*str)
        av_dict_set(&s->metadata, key, str, 0);
}

/**
 * Parse an ID3v1 tag
 *
 * @param buf ID3v1_TAG_SIZE long buffer containing the tag
 */
static int parse_tag(AVFormatContext *s, const uint8_t *buf)
{
    char str[5];
    int genre;

    if (!(buf[0] == 'T' &&
          buf[1] == 'A' &&
          buf[2] == 'G'))
        return -1;
    get_string(s, "title",   buf +  3, 30);
    get_string(s, "artist",  buf + 33, 30);
    get_string(s, "album",   buf + 63, 30);
    get_string(s, "date",    buf + 93,  4);
    get_string(s, "comment", buf + 97, 30);
    if (buf[125] == 0 && buf[126] != 0) {
        snprintf(str, sizeof(str), "%d", buf[126]);
        av_dict_set(&s->metadata, "track", str, 0);
    }
    genre = buf[127];
    if (genre <= ID3v1_GENRE_MAX)
        av_dict_set(&s->metadata, "genre", ff_id3v1_genre_str[genre], 0);
    return 0;
}

void ff_id3v1_read(AVFormatContext *s)
{
    int ret;
    uint8_t buf[ID3v1_TAG_SIZE];
    int64_t filesize, position = avio_tell(s->pb);

    if (s->pb->seekable) {
        /* XXX: change that */
        filesize = avio_size(s->pb);
        if (filesize > 128) {
            avio_seek(s->pb, filesize - 128, SEEK_SET);
            ret = avio_read(s->pb, buf, ID3v1_TAG_SIZE);
            if (ret == ID3v1_TAG_SIZE) {
                parse_tag(s, buf);
            }
            avio_seek(s->pb, position, SEEK_SET);
        }
    }
}
